本篇文章同步發表於 個人部落格 Jim's Blog
Blazor 應用程式有提供從 JavaSript 呼叫 .NET Method的方法,當然反過來也可以從 .NET Method 叫用 JavaScript Function,打通兩個語言之間的邊界,讓互動性更上一層樓!
在 Blazor 中想要撰寫JS,有五種方式可以挑選
<head>
標記 中載入指令碼 (不推薦)<head>
<script>
window.jsMethod = () => {
alert("Hello World!")
};
</script>
</head>
不推薦寫在 head
標記內的原因有兩個
<body>
標記中載入指令碼<body>
...
<script src="_framework/blazor.{webassembly|server}.js"></script>
<script>
window.jsMethod = () => {
alert("Hello World!")
};
</script>
</body>
<body>
...
<script src="_framework/blazor.{webassembly|server}.js"></script>
<script src="{要引入的Javascript檔名.js}"></script>
</body>
.js
結尾,看起來像這樣.razor.js
Pages/Index.razor.js
export function showHello() {
return prompt('Hello');
}
Pages/Index.razor
module = await JS.InvokeAsync<IJSObjectReference>(
"import", "./Pages/Index.razor.js");
autostart="false"
Blazor.start().then
Blazor 啟動後,在建立Sctipt區塊填入JS檔案<body>
...
<script src="_framework/blazor.{webassembly|server}.js"
autostart="false"></script>
<script>
Blazor.start().then(function () {
var customScript = document.createElement('script');
customScript.setAttribute('src', 'scripts.js');
document.head.appendChild(customScript);
});
</script>
</body>
不要把
<script>
放在 .razor 內,因為 Blazor 無法動態更新
想要在 .Net 內呼叫 JS 方法,首先需要 IJSRuntime
這一個介面,他的實作由 Blazor 框架註冊,這部分介紹兩個方法
JavaScriptRun.razor.js
export function getHello() {
return 'Hello';
}
@page "/JsRun"
@inject IJSRuntime JS
<button @onclick="getHello">Click</button>
<p>@text</p>
@code {
private IJSObjectReference? module;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import", "./Pages/JavaScriptRun.razor.js");
}
}
private string text{ get; set; }
private async Task getHello()
{
text = await module.InvokeAsync<string>("getHello");
}
}
這邊採用的是上面的第四種方式: 從外部 JavaScript 檔案載入指令碼 (.js) 與元件共置
@page "/JsRun"
@inject IJSRuntime JS
<button @onclick="AlertHello">Click</button>
@code {
private async Task AlertHello()
{
await JS.InvokeVoidAsync("alert", "Hello");
}
}
JS Interop 呼叫預設都是非同步的,如果應用程式只有在 Blazor WebAssembly 執行,可以選擇進行同步 JS Interop 呼叫,這樣會稍微少一些額外負荷,而且可能會縮短轉譯週期
接下來我們說說,從 JS 呼叫 .NET Method的方法
DotNet.invokeMethodAsync('{組件名稱}', '{方法名稱}', {參數});
想要讓 JS可以呼叫到 .NET 有幾個先決條件
[JSInvokable]
AttributeJsRun.razor
@page "/JsRun"
<button onclick="getString()">
Click
</button>
@code {
[JSInvokable]
public static async Task<string> GetHello()
{
await Task.CompletedTask;
return "Hello";
}
}
仔細看在Button Click的事件,沒有加入 @
代表這不是 Razor 語法
JsRun.js
window.getString = () => {
DotNet.invokeMethodAsync('BlazorApp1', 'GetHello')
.then(data => {
console.log(data);
});
};
填入組件名稱以及方法名稱,就可以從JS呼叫 .NET 靜態方法了
JsRun.razor
@page "/JsRun"
@implements IDisposable
@inject IJSRuntime JS
<button @onclick="JsCallInstanceMethod">
按我呼叫C# 執行個體方法
</button>
<P>@result</P>
@code {
private string? result;
private DotNetObjectReference<JsRun>? objRef;
public async Task JsCallInstanceMethod()
{
objRef = DotNetObjectReference.Create(this);
result = await JS.InvokeAsync<string>("sayHello", objRef);
}
[JSInvokable]
public string GetHelloMessage()
{
return $"Hello !";
}
public void Dispose()
{
objRef?.Dispose();
}
}
JsRun.razor.js
window.sayHello = (dotNetHelper) => {
return dotNetHelper.invokeMethodAsync('GetHelloMessage');
};
呼叫執行個體方法稍稍複雜了一些,我們一步一步看他是怎麼執行的
JsCallInstanceMethod()
,建立新的 DotNetObjectReference<JsRun>
執行個體sayHello
Function,調用 .NET GetHelloMessage
方法,完成後結果回傳給result
DotNetObjectReference
建立的執行個體要被放在 Dispose
內就這樣我們一來一回的完成兩種語言的相互呼叫,在JS互通其實還有很多好玩的東西和細節,像是可以直接把stream
從 JS 傳輸到 .NET 、Blazor 在 JavaScript Module 有啟用JavaScript 隔離再也不用擔心全域汙染的問題......等等,一時半刻也說不清,在後續的章節慢慢補充說明
寫完這篇才發現忘記介紹在 Blazor 該怎麼寫 CSS 了XDD
下一篇文章回頭說說 Blazor 元件 CSS